package com.mazaiting.instructions.math;

import com.mazaiting.instructions.base.NoOperandsInstruction;
import com.mazaiting.rtda.MtFrame;
import com.mazaiting.rtda.MtOperandStack;

/**
 * 位移指令
 *
 * @author mazaiting
 * @since 2021/8/14
 */
public class ShInstruction {

    /**
     * int左位移
     * int变量只有32位，所以只取v1的前5个比特就足够表示位移位数
     */
    public static class IShl extends NoOperandsInstruction {
        @Override
        public void execute(MtFrame frame) {
            MtOperandStack stack = frame.getOperandStack();
            // v1指出要移位多少比特
            int v1 = stack.popInt();
            // v2是要进行位移操作的变量
            int v2 = stack.popInt();
            // 获取 v1 的前 5 个比特
            int bits = v1 & 0x1f;
            int result = v2 << bits;
            stack.pushInt(result);
        }

        @Override
        public String toString() {
            return "ishl";
        }
    }

    /**
     * int算术右位移
     * int变量只有32位，所以只取v1的前5个比特就足够表示位移位数
     */
    public static class IShr extends NoOperandsInstruction {
        @Override
        public void execute(MtFrame frame) {
            MtOperandStack stack = frame.getOperandStack();
            // v1指出要移位多少比特
            int v1 = stack.popInt();
            // v2是要进行位移操作的变量
            int v2 = stack.popInt();
            // 获取 v1 的前 5 个比特
            int bits = v1 & 0x1f;
            int result = v2 >> bits;
            stack.pushInt(result);
        }

        @Override
        public String toString() {
            return "ishr";
        }
    }

    /**
     * int逻辑右位移
     * int变量只有32位，所以只取v1的前5个比特就足够表示位移位数
     */
    public static class IUShr extends NoOperandsInstruction {
        @Override
        public void execute(MtFrame frame) {
            MtOperandStack stack = frame.getOperandStack();
            // v1指出要移位多少比特
            int v1 = stack.popInt();
            // v2是要进行位移操作的变量
            int v2 = stack.popInt();
            // 获取 v1 的前 5 个比特
            int bits = v1 & 0x1f;
            int result = v2 >>> bits;
            stack.pushInt(result);
        }

        @Override
        public String toString() {
            return "iushr";
        }
    }

    /**
     * long左位移
     * long变量有64位，所以取v2的前6个比特。
     */
    public static class LShl extends NoOperandsInstruction {
        @Override
        public void execute(MtFrame frame) {
            MtOperandStack stack = frame.getOperandStack();
            // v1指出要移位多少比特
            int v1 = stack.popInt();
            // v2是要进行位移操作的变量
            long v2 = stack.popLong();
            // 获取 v1 的前 6 个比特
            int bits = v1 & 0x3f;
            long result = v2 << bits;
            stack.pushLong(result);
        }

        @Override
        public String toString() {
            return "lshl";
        }
    }

    /**
     * long算术右位移
     * long变量有64位，所以取v2的前6个比特。
     */
    public static class LShr extends NoOperandsInstruction {
        @Override
        public void execute(MtFrame frame) {
            MtOperandStack stack = frame.getOperandStack();
            // v1指出要移位多少比特
            int v1 = stack.popInt();
            // v2是要进行位移操作的变量
            long v2 = stack.popLong();
            // 获取 v1 的前 6 个比特
            int bits = v1 & 0x3f;
            long result = v2 >> bits;
            stack.pushLong(result);
        }

        @Override
        public String toString() {
            return "lshr";
        }
    }

    /**
     * long逻辑右位移
     * long变量有64位，所以取v2的前6个比特。
     */
    public static class LUShr extends NoOperandsInstruction {
        @Override
        public void execute(MtFrame frame) {
            MtOperandStack stack = frame.getOperandStack();
            // v1指出要移位多少比特
            int v1 = stack.popInt();
            // v2是要进行位移操作的变量
            long v2 = stack.popLong();
            // 获取 v1 的前 6 个比特
            int bits = v1 & 0x3f;
            long result = v2 >>> bits;
            stack.pushLong(result);
        }

        @Override
        public String toString() {
            return "lushr";
        }
    }
}
